package com.jwater.core.manager.job.timer;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 定时器以一天的0时作为基准，按照intreval往后推算任务时间，譬如间隔是1分钟，那一天的任务时间点有00:01:00、00:02:00、00:03:00等，
 * 定时器的触发时间跟任务时间不一定相同，只有在delay设置为0时才相同，但delay设置为10秒时，触发时间为00:01:10秒触发执行00:01:00时间的任务
 *
 * @description:
 * @author: jnner
 * @createDate: 2021/2/5
 * @version: 1.0
 */
public class BaseTimer {
    protected static Logger logger = LoggerFactory.getLogger(BaseTimer.class);

    protected ScheduledExecutorService executorService;
    protected TimerTask task;
    private long interval;
    private long delay;
    private int threadPoolSize;
    protected boolean isRunning = true;
    private long executeCount = 0;
    private long firstTime = 0;

    public BaseTimer(TimerTask task, long interval, long delay, int threadPoolSize) {
        this.task = task;
        this.interval = interval;
        this.delay = delay;
        this.threadPoolSize = threadPoolSize;
    }

    public void start() {
        isRunning = true;
        executorService = Executors.newScheduledThreadPool(threadPoolSize);
        long currentTime = System.currentTimeMillis();
        long waitTime = (interval - currentTime % interval + delay % interval) % interval;
        executorService.scheduleAtFixedRate(new DoWorkRunnable(), waitTime, interval, TimeUnit.MILLISECONDS);
    }

    public void stop() {
        isRunning = false;
        if (executorService != null) {
            executorService.shutdownNow();
        }
    }

    protected class DoWorkRunnable implements Runnable {
        @Override
        public void run() {
            try {
                long time = 0;
                if (firstTime == 0) {
                    long currentTime = System.currentTimeMillis() - delay;
                    time = currentTime - currentTime % interval;
                    firstTime = time;
                } else {
                    time = firstTime + executeCount * interval;
                }
                if (isRunning) {
                    task.doWork(time);
                } else {
                    logger.warn("not running");
                }
            } catch (Exception e) {
                logger.error(e.toString(), e);
            } finally {
                executeCount++;
            }
        }
    }
}
